#!/usr/sbin/rsct/perl5/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
#"@(#)33   1.28   src/rsct/rmc/cli/bin/lsrsrc.perl, rmccli, rsct_rpyxh, rpyxht1f3 8/5/02 09:08:25"
######################################################################
#                                                                    #
# Module: lsrsrc                                                     #
#                                                                    #
# Purpose:                                                           #
#   lsrsrc - Lists (displays) resources or a resource class.         #
#                                                                    #
# Syntax:                                                            #
#   lsrsrc [-h] [-s "Selection_string"] [-A p|d|b] [-p Property]     #
#          [-a] [-l|-i|-t|-d|-D Delimiter] [-x] [-T] [-V]            #
#          [Resource_class [Attr...]]                                #
#                                                                    #
#   lsrsrc [-h] [-s "Selection_string"] -r  [-a]                     #
#          [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] [Resource_class]   #
#                                                                    #
#   lsrsrc [-h] -c [-A p|d|b] [-p Property] [-a]                     #
#          [-l|-i|-t|-d|-D Delimiter] [-x] [-T] [-V]                 #
#          [Resource_class [Attr...]                                 #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes the command's usage statement to stdout.    #
#   -c      Class. Displays the attributes for the resource class.   #
#           By default, the resource attributes, not the resource    #
#           class, are displayed. This flag overrides the -r flag.   #
#   -r      Resource Handle. Displays the resource handles for the   #
#           resources that match the specified selection string or   #
#           all resources when no selection string is specified.     #
#   -s "Selection string" Specifies the selection string. All        #
#           selection strings must be enclosed within either double  #
#           or single quotation marks. If the selection string       #
#           contains double quotation marks, enclose the entire      #
#           selection string in single quotation marks. For example: #
#           -s 'Name == "testing"'                                   #
#           -s 'Name ?= "test"'                                      #
#           Only persistent attributes can be listed in a selection  #
#           string.                                                  #
#   -A      Attribute type. By default only persistent attributes    #
#           are displayed. This flag can be used only when no        #
#           attribute names are specified on the command line.       #
#           p - Displays only persistent attributes.                 #
#           d - Displays only the dynamic attributes.                #
#           b - Displays both persistent and dynamic attributes.     #
#           For best performance, specify the -A p flag.             #
#   -p Property Displays attributes with the specified property. By  #
#           default, only public attributes are displayed. To        #
#           display all the attributes regardless of the property,   #
#           use the -p 0 flag. Use this flag in conjunction with     #
#           the -A flag when no attributes are specified on the      #
#           command line. Refer to ct_mc.h for persistent and        #
#           dynamic property values. An or-ing of the properties     #
#           will be accepted to display only attributes that have    #
#           any of the specified properties.                         #
#   -a      All nodes. The lsrsrc command applies to all nodes in    #
#           the cluster. The cluster scope is determined by the      #
#           environment variable CT_MANAGEMENT_SCOPE. If it is not   #
#           set, first the management domain scope is used, then     #
#           peer domain scope, and then local scope is used until    #
#           the scope is a valid scope for the command. The command  #
#           will run once for the first valid scope found.           #
#   -l      Long formatted output. Each attribute is displayed on a  #
#           separate line. This is the default display format. If    #
#           the lsrsrc command is issued with the -l flag, but       #
#           without a resource class name, the -l flag is ignored    #
#           when the command returns the list of defined resource    #
#           class names.                                             #
#   -i      Input format. Generates a template of the Resource Data  #
#           Input File which can then, after appropriate editing, be #
#           used as input to the mkrsrc command. The output is       #
#           displayed in long (stanza) format. All required and      #
#           optional attributes that can be used to define a         #
#           resource are displayed. The attribute data type is       #
#           displayed as the value in the Attr=value pairs. It is    #
#           suggested that when you use this flag, the output of the #
#           lsrsrc command be directed to a file.                    #
#           The -i flag overrides the -Ad, and -Ab flags and is      #
#           ignored if -r is specified.                              #
#   -t      Tabular formatted output. Each attribute is displayed    #
#           in a separate column, one resource per line.             #
#   -d      Delimiter-formatted output. The default delimiter is     #
#           a colon (:). Use the -D flag if you wish to change       #
#           the default delimiter.                                   #
#   -D Delimiter Delimiter formatted output using the specified      #
#           delimiter. Use this flag to specify something other than #
#           the default colon (:). An example is when the data to be #
#           displayed contains colons. Use this flag to specify a    #
#           delimiter of one or more characters.                     #
#   -x      Exclude header. Suppresses header printing.              #
#   -T      Trace. Writes the command's trace messages to standard   #
#           error. For your software-service organization use only.  #
#   -V      Verbose. Writes this command's verbose messages to       #
#           standard output.                                         #
#                                                                    #
# Operands:                                                          #
#   Resource_class  Resource class name. The name of the resource    #
#                   class whose resources you wish displayed. Zero   #
#                   or one Resource_class operand can be specified.  #
#                   If no Resource_class operand is specified, a     #
#                   list of all resource class names is displayed.   #
#                                                                    #
#  Attr             Attribute name. Both persistent and dynamic      #
#                   attribute names may be specified to control      #
#                   which attributes are displayed and their order.  #
#                   Zero or more attribute may be specified.         #
#                   Attributes must be separated by spaces. If no    #
#                   attribute names are specified, the -A p|d|b flag #
#                   controls whether only persistent attributes,     #
#                   only dynamic attributes, or both persistent and  #
#                   dynamic attributes are displayed.                #
#                                                                    #
# Description:                                                       #
#   The lsrsrc command is used to list the persistent and dynamic    #
#   attributes and their values of either a resource or resource     #
#   class.                                                           #
#                                                                    #
#   When no Attr operand is specified, only attributes that are      #
#   defined as public are displayed. Use the -p flag to override     #
#   this default. When no Attr operand is specified, the -A p|d|b    #
#   flag controls whether only persistent, or only dynamic or both   #
#   persistent and dynamic attributes and their values are displayed.#
#                                                                    #
#   When one or more attribute names are specified, exactly the      #
#   attribute names specified and their values are displayed in the  #
#   order specified, provided that each of the specified attribute   #
#   names are valid.                                                 #
#                                                                    #
#   To get a list of all of the resource classes, enter the lsrsrc   #
#   command with no operands.                                        #
#                                                                    #
#   Specify the -c flag to display a list of the resource class      #
#   attributes and values.                                           #
#                                                                    #
#   Specify the -r flag to display only the resource handles         #
#   linked with the resources for the specified class.               #
#                                                                    #
#   Specify the -a flag to display resources from all nodes in the   #
#   cluster.                                                         #
#                                                                    #
#   By default the resource attributes and values are displayed in   #
#   long format. Use the -t, -d, or -D flags for the resources       #
#   to be displayed in tabular or delimiter formatted output.        #
#                                                                    #
#   For best performance, specify either the -A p flag or only       #
#   persistent attributes as operands.                               #
#                                                                    #
#   Note: Any attribute that has a data type defined as ct_none (for #
#         example, a Quantum) is not listed by the lsrsrc command.   #
#         RMC does not return attribute values for attributes that   #
#         are defined as Quantum. To list attribute definitions,     #
#         use the lsrsrcdef command.                                 #
#                                                                    #
# Exit Values:                                                       #
#   0  MC_CLI_SUCCESS        Command completed successfully.         #
#   1  MC_CLI_RMC_ERROR      Command terminated due to an underlying #
#                            RMC error.                              #
#   2  MC_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  MC_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  MC_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  MC_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            Resource name as the Resource operand.  #
#                                                                    #
# Examples:                                                          #
#   1. List all the resource class names                             #
#      lsrsrc                                                        #
#   2. List IBM.Processor resource persistent attributes.            #
#      lsrsrc IBM.Processor                                          #
#   3. List IBM.Host resource dynamic attributes.                    #
#      lsrsrc -Ad IBM.Host                                           #
#   4. List IBM.Condition resource class persistent attributes.      #
#      lsrsrc -c IBM.Condition                                       #
#   5. List IBM.Processor resource persistent attributes Name and    #
#      ProcessorType in tabular format (long is the default format). #
#      lsrsrc -t IBM.Processor Name ProcessorType                    #
#   6. List only the resource handles associated with IBM.Condition  #
#      resources that have a Name containing the word Page.          #
#      lsrsrc -r -s 'Name ?= "Page"' IBM.Condition                   #
#   7. List both Persistent and Dynamic Attributes                   #
#      lsrsrc -Ab IBM.Foo                                            #
#   8. List specific Persistent and Dynamic Attributes               #
#      lsrsrc IBM.Foo Name OpState                                   #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the lsrsrc man page in /usr/sbin/rsct/man.                       #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /usr/sbin/rsct/msgmaps/mccli.lsrsrc.map - message mapping        #
#   /usr/sbin/rsct/msgmaps/mccli.mccli.map - message mapping         #
#                                                                    #
# Outputs:                                                           #
#   stdout - display of the resource or resource class attr & values.#
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  MC_cli_utils.pm, MC_cli_rc.pm, MC_cli_display_utils.pm #
#             CT_cli_utils.pm, CT_cli_input_utils                    #
#   Extensions:  CT::MC, CT::MCerr, CT::CT                           #
#   Perl library routines: Getopt::Std                               #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   990924 SAB 48420: Initial design & write.                        #
#   010311 SAB 63852: Prepared for GA.                               #
#   020220 JAC 79829: Make some changes for distributed rmc for when #
#                     some nodes respond and some don't.             #
#   020716 JAC 84819: Change -a to -A and use -a for all in cluster. #
#   020801 JAC 85417: Update usage message.                          #
#   020802 JAC 84820: Add -i flag.                                   #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#       * List either the resource class (-c) or resource attributes.#
#       * List only persistent attributes (-A p - the default)       #
#       * List only dynamic attributes    (-A d)                     #
#       * List both persistent and dynamic attributes (-A b)         #
#       * List only the attributes that were specified on the        #
#         command line.                                              #
# B. Initialize a session with RMC.                                  #
# C. Query the definition of the attributes.                         #
#       * Filter the public attributes or the attributes with the    #
#         specified properties.                                      #
#       * Determine which attribute names are persistent and which   #
#         are dynamic. Only query the definitions of both pers & dyn #
#         when necessary. We need to determine which are which so    #
#         we pass the right attribute names on the query_p_select    #
#         versus the query_d_select.                                 #
# D. Query RMC for the attribute values.                             #
# E. Display the resource attributes and values.                     #
# F. Cleanup.                                                        #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std; 

use CT::CT qw(CT_RSRC_HANDLE_PTR);

use autouse CT_cli_utils => qw(
    printIMsg
    printEMsg
);
use autouse CT_cli_input_utils => qw(
    string_to_rsrc_handle
);

use CT::MC qw(
    :mc_pattr_props_t
    :mc_qdef_opts_t

    qdef_resource_class_bp
    query_p_select_bp
    query_d_select_bp
    class_query_p_bp
    class_query_d_bp
    free_response
);

use CT::MCerr;

use MC_cli_rc qw(:return_codes);
use autouse MC_cli_utils => qw(
    init_session
    term_session
    enumerate_resources
    qdef_resource_class
    get_p_attr_defs
    get_d_attr_defs
    build_HoAttr
    translate_lsAOpt
    error_exit
    printCIMsg 
    printCEMsg
);
use autouse MC_cli_display_utils => qw(
    display_resource_class_names
    display_resource_data
    display_joined_resource_data
);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
$TRUE = 1;
$FALSE = 0;

$Verbose = $FALSE;                      # default - verbose turned off

# By default output is written in long format.
$Opt_Long_Format  = $TRUE;              # default - see -l (long form)
$Opt_Table_Format = $FALSE;             # default - see -t (tabular) 
$Opt_Delm_Format  = $FALSE;             # default - see -d (delimiter)
$Opt_Delm_Str = ":";                    # default - see -D (colon :) 
$Opt_No_HDR = $FALSE;                   # default - see -x
$Opt_LS_Class = $FALSE;                 # default - see -c
$Opt_LS_DAttr = $FALSE;                 # default - see -A p 
$Opt_LS_PAttr = $TRUE;                  # default - see -A p
$Opt_LS_RHandle = $FALSE;               # default - see -r 
$Opt_LS_Cluster = $FALSE;               # default - see -a 
$Opt_LS_Input_File = $FALSE;            # default - see -i 

$Fkey_Attr_Name = "MC_FKEY*PATTR_TO_DATTR_KEY*MC_FKEY";
                                        # HoPAttr to HoDAttr foreign
                                        # key attr name.

$PROGNAME = "lsrsrc";                   # Program Name for messages
$MSGCAT = "mccli.cat";                  # msg catalogue for this cmd

$CTDIR = "/usr/sbin/rsct";              # RSCT root directory
$CTBINDIR = "$CTDIR/bin";               # Cluster Bin directory path
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn.
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps used by $LSMSG
%Cleanup = ();                          # Hash of items to cleanup
                                        # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
@attributes = ();                       # Attr names from cmd line
@p_attributes = ();                     # Pers attr from cmd line
@d_attributes = ();                     # Dynam attr from cmd line
my $req_properties = 0;                 # Requested properties
                                        # default, public properties

# The reason that we keep a separate list of the keys that are in 
# the hash - is that way we can preserve the ordering that RMC 
# returned the attributes. Hashes don't maintain order. 
# Arrays / Lists do. 
@LoPAttr = ();                          # attr names keys in HoPAttr
%HoPAttr = ();                          # hash of pers attr & values

@LoDAttr = ();                          # attr names keys in HoDAttr
%HoDAttr = ();                          # hash of dynam attr & values

#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
my $rc = 0;

# look for the old -a option for attributes and change it to -A
@ARGV = translate_lsAOpt(@ARGV);

# parse the command line, exit if there are errors 
($rc, $resource, $select_str, $req_properties, @attributes) = 
    &parse_cmd_line;
($rc == 0) || error_exit($rc);

# if -a was specified to list all nodes, make sure CT_MANAGEMENT_SCOPE
# is set.  If it isn't, set it to 4, DM/SR/Local 
if ($Opt_LS_Cluster && !defined $ENV{CT_MANAGEMENT_SCOPE}) {
   $ENV{CT_MANAGEMENT_SCOPE} = 4;
}

# initialize a session with RMC
($rc, $session) = init_session();
($rc == 0) || error_exit($rc);
$Cleanup{Session} = $session;

# if no resource names specified display the list of resource
# names.
if (!$resource) {               # No resource operands
    # Need a Response Class
    my $response = CT::MC::qdef_rsrc_class_rsp_t->new;

    # Let this subroutine handle the real call to the extension
    # and dealing with all of the return codes..
    $rc = qdef_resource_class($session, "", $response, 0);
    ($rc == 0) || error_exit($rc); 
    
    # Display the Resource Class Definitions
    $rc = display_resource_class_names($response, $Opt_No_HDR, 
        $Opt_Table_Format, 0, $Opt_Delm_Format, $Opt_Delm_Str);
    ($rc == 0) || error_exit($rc);

    # Free the response - if there was one
    if ($response->array_count > 0) {
        $rc = CT::MC::free_response($response);
        ($rc == 0) || error_exit($rc);
    }
}
elsif ($Opt_LS_RHandle) {
    # Call the MC_cli_utils::enumerate_resources function, which calls
    # RMC function mc_enumerate_resources_bp, to get a list
    # of resource handles that match the selection string that
    # was specified by the user. These resource handles are the 
    $rc = enumerate_resources($session, $resource, $select_str, 
        \@resource_handles);
    ($rc == 0) || error_exit($rc);

    # Format and Display the resource handles
    format_resource_handles(\@resource_handles, \@LoPAttr, \%HoPAttr);

    # Display the Resource Class Persistent Attributes
    $rc = display_resource(\@LoPAttr, \@LoPAttr, \%HoPAttr);
    ($rc == 0) || error_exit($rc);
}

else {

# If any attributes were specified on the command line we need to 
# determine which of these are persistent and which are dynamic. 
# In addition we need to select which attributes we should display
# based on what the attribute property is and what properties have
# been requested. By default only public attributes are displayed.
# This can be overriden with the -p flag or by specifying attribute
# names on the command line. We will not display attributes with 
# data type of ct_none since they are QUANTUM and RMC will not 
# return values of attributes that are QUANTUM.

my @cmd_line_attributes = @attributes; 
my $query_rc = 0;
$rc = select_attr($session, $resource, $req_properties, \@attributes,
    \@p_attributes, \@d_attributes); 
($rc == 0) || error_exit($rc);

if ($Opt_LS_Class && $Opt_LS_PAttr && scalar(@p_attributes) > 0) {
    # Let the subroutine make the call to the extension, and
    # handle all the assorted potential errors.
    $rc = class_query_p($session, $resource, \@p_attributes, 
        \@LoPAttr, \%HoPAttr);
    ($rc == 0) || error_exit($rc); 
}

if ($Opt_LS_Class && $Opt_LS_DAttr && scalar(@d_attributes) > 0) {
    # Let the subroutine make the call to the extension, and
    # handle all the assorted potential errors.
    $rc = class_query_d($session, $resource, \@d_attributes, 
        \@LoDAttr, \%HoDAttr);
    ($rc == 0) || error_exit($rc);
}

if (!$Opt_LS_Class && $Opt_LS_PAttr && scalar(@p_attributes) > 0) {
    # Let the subroutine make the call to the extension, and
    # handle all the assorted potential errors.
    $rc = query_p_select($session, $resource, $select_str,
            \@p_attributes, \@LoPAttr, \%HoPAttr);
    $query_rc = $rc
#   ($rc == 0) || error_exit($rc);
}

if (!$Opt_LS_Class && $Opt_LS_DAttr && scalar(@d_attributes) > 0) {
    # Let the subroutine make the call to the extension, and
    # handle all the assorted potential errors.
    $rc = query_d_select($session, $resource, $select_str,
        \@d_attributes, \@LoDAttr, \%HoDAttr);
    $query_rc = $rc
#   ($rc == 0) || error_exit($rc);
}

# Display exactly the attribute that were specified on the  
# command line or only the ones that RMC actually returned when 
# no attributes were specified on the command line. 
# Because of Variety support in RMC you may get less attributes back 
# from RMC then you asked for. Not all attributes have values 
# for a particular resource.
if (scalar(@cmd_line_attributes) == 0) {
    if ($Opt_LS_PAttr && !$Opt_LS_DAttr) {
        @p_attributes = @LoPAttr;
        shift @p_attributes;            # get rid of the *MC_FKEY...
    }
    elsif (!$Opt_LS_PAttr && $Opt_LS_DAttr) {
        @d_attributes = @LoDAttr;
        shift @d_attributes;            # get rid of the *MC_FKEY...
    }
    else {
        @attributes = @LoDAttr;
        shift @attributes;              # get rid of the *MC_FKEY...
        unshift @attributes, @LoPAttr;
        shift @attributes;              # get rid of the *MC_FKEY...
    }
}

# Display the attributes
if ($Opt_LS_PAttr && !$Opt_LS_DAttr) {
    # Display the Persistent Attributes
    $rc = display_resource(\@p_attributes, \@LoPAttr, \%HoPAttr);
}
elsif (!$Opt_LS_PAttr && $Opt_LS_DAttr) {
    # Display the Dynamic Attributes
    $rc = display_resource(\@d_attributes, \@LoDAttr, \%HoDAttr);
}
else {
    # Display both Persistent and Dynamic Attributes
    $rc = display_joined_resource(\@attributes, \@LoPAttr, \%HoPAttr, 
        \@LoDAttr, \%HoDAttr);
}
($query_rc == 0) || error_exit($query_rc);
($rc == 0) || error_exit($rc);

} # end else

# Cleanup 
$rc = term_session($session);
exit($rc);


#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line - Parse the command line for options and operands.  #
#   Set appropriate global variables as outlined below, make sure we #
#   have a valid combination of arguments / options.                 #
#                                                                    #
# Return:                                                            #
#   $rc   0                  Command line parsed fine, no problem.   #
#         SR_CLI_BAD_FLAG    Command line contained a bad flag.      #
#   $resource                Name of resource to be displayed.       #
#   $select_str              Selection string.                       #
#   $properties              Attributes having these properties      #
#                            should be displayed.                    #
#   @attributes              Array of attributes to be displayed.    #
#                                                                    #
# Global Variables Modified:                                         #
#   $Opt_Current       output   True (-c) print current cluster info #
#   $Opt_LS_Class      output   True (-c) display the resource       #
#                               class attributes.                    #
#   $Opt_LS_DAttr      ouptput  True (-A d) display the resource     #
#                               dynamic attributes.                  #
#   $Opt_LS_PAttr      output   True (-A p) display the resource     #
#                               persistent attributes.               #
#   $Opt_LS_RHandle    output   True (-r) displays the resource      #
#                               handles for specified resource.      #
#   $Opt_LS_Cluster    output   True (-a) list all nodes             #
#   $Opt_LS_Input_File output   True (-i) input file format          #
#   $Opt_Long_Format   output   True (-l) print one entry per line   #
#   $Opt_Table_Format  output   True (-t) print in table format.     #
#   $Opt_Delm_Format   output   True (-d|-D) print delimitter        #
#                               separated output.                    #
#   $Opt_Delm_Str      output   the string to use as the delimitter, #
#                               default is colon (:).                #
#   $Opt_No_HDR        output   True (-x) print without header       #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my(@original_argv) = @ARGV;
my $resource = "";
my $select_str = "";
my $properties = 0;
my @attributes = ();
my %opts = ();

# Process the command line...
if (!&getopts('haA:cp:rs:dD:tlixVT', \%opts)) { # Gather options; if error
    &print_usage;                       # display proper usage
    return MC_CLI_BAD_FLAG;             # return bad rc - bad flag 
}

# Always accept the -h help flag regardless of other flags or operands
if (defined $opts{h}) {                 # -h, help request  
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
}

# If no operands in lsrsrc that is OK, it just means display
# a list of all Resource Class Names

# Get the arguments...
# Operands:  [resource [attr...]]
if ($#ARGV >= 0) {
    $resource = shift @ARGV;            # user specified resources
    @attributes = @ARGV;                # array of attribute names
}

# See which options/flags were used...

if (defined $opts{c}) {                 # -c, rsrc class definitions
    $Opt_LS_Class = $TRUE;
    if (defined $opts{s}) { 
        printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-s"); 
        &print_usage;    
        return MC_CLI_BAD_FLAG;
    }
}

if (defined $opts{r}) {                 # -r, display resource handles
    $Opt_LS_RHandle = $TRUE;
    if (defined $opts{c}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
}

if (defined $opts{s}) {                 # -s "selection_string"
    $select_str = $opts{s};
}

if (defined $opts{a}) {                 # -a, list all nodes
    $Opt_LS_Cluster = $TRUE;
}

if (defined $opts{A}) {                 # -A, attribute type 
    # -A b  default display both dynamic & persistent attributes
    if ($opts{A} eq "b") {              # -A b, ls dynamic & pers attr
        $Opt_LS_DAttr = $TRUE;
        $Opt_LS_PAttr = $TRUE;
    }
    elsif ($opts{A} eq "d") {           # -A d, ls dynamic attributes
        $Opt_LS_DAttr = $TRUE; 
        $Opt_LS_PAttr = $FALSE;
    } 
    elsif ($opts{A} eq "p") {           # -A p, ls persistent attr
        $Opt_LS_PAttr = $TRUE;
        $Opt_LS_DAttr = $FALSE;
    }
    else {
        # -A flag requires p persistent | d dynamic | b both 
        printCEMsg("EMsgMCcliImproperUsageFlag", "-A $opts{A}");   
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
}
else {
    # Default - display only persistent attributes 
    $Opt_LS_DAttr = $FALSE; 
    $Opt_LS_PAttr = $TRUE; 
}   

if (defined $opts{i}) {                 # -i input file format
    $Opt_LS_Input_File = $TRUE;
    # Default to displaying only required for define and public.
    # User should enter -p <property> if they want other properties.
    # don't default to optional for define.  NodeIDs and NodeNameList together
    # don't like each other on mkrsrc.
    $properties = MC_RSRC_PATTR_REQD_FOR_DEFINE | MC_RSRC_PATTR_PUBLIC;
    # -i overrides -Ad and -Ab (-i only makes sense with persistent attrs)
    $Opt_LS_DAttr = $FALSE;
    $Opt_LS_PAttr = $TRUE;
}

if (defined $opts{p}) {                 # -p Property
    $properties = $opts{p};
    # Make sure properties is a number (hex, octal or decimal)
    if ($properties !~ /^(0x|\d+)\d*/) {
        printCEMsg("EMsgMCcliImproperUsageFlag", "-p $opts{p}");
        return MC_CLI_USER_ERROR;       
    }
    # Convert properties specified in hex or octal to decimal
    $properties = oct $properties if $properties =~ /^0/;

    # Just some mininmal range checking - valid property values only 
    # range between 0x0001 to 0x0020 but allow for growth here
    # -p 0 means display attributes with any property
    if ($properties < hex("0x0000") || $properties > hex("0xFFFF")) {
        printCEMsg("EMsgMCcliImproperUsageFlag", "-p $opts{p}");
        return MC_CLI_USER_ERROR;
    }
    if ($properties == 0) {
        $properties = hex("0xFFFF");
    }
}
elsif (!defined $opts{i}) {
    # Default to display only public attributes
    # Dynamic and Persistent Public properties are both 0x0020
    $properties = MC_RSRC_PATTR_PUBLIC; # Default to Public properties
}


# When attributes are specified they can be persistent or dynamic
# And they can have any property
# This will override -A or -p flag even if it was specified.
if (scalar(@attributes) > 0) {
    $Opt_LS_DAttr = $TRUE;
    $Opt_LS_PAttr = $TRUE;
    $properties = 0xFFFF;
}


# The -l overrides the -t which overrides the -d which overrides -D
# -i always displays in long format
# Long is the default display format 
if (defined $opts{l} || defined $opts{i}) {
    $Opt_Long_Format = $TRUE;
}
elsif (defined $opts{t}) {
    $Opt_Table_Format = $TRUE;          # -t tabular format
    $Opt_Long_Format = $FALSE;
}
elsif (defined $opts{d}) {              # -d delimitter format
    $Opt_Delm_Format = $TRUE;
    $Opt_Long_Format = $FALSE;
}
elsif (defined $opts{D}) {              # -D <delimitter> format
    $Opt_Delm_Format = $TRUE;
    $Opt_Long_Format = $FALSE; 
    $Opt_Delm_Str = $opts{D};
}

if (defined $opts{x}) {                 # -x do not print header
    $Opt_No_HDR = $TRUE;
}

if (defined $opts{T}) {                 # -T turn trace on
    $Trace = $TRUE;
}

if (defined $opts{V}) {                 # -V turn verbose mode on 
    $Verbose = $TRUE;
}

return(0, $resource, $select_str, $properties, @attributes); # success
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsglsrsrcUsage2");
}   # end print_usage


#--------------------------------------------------------------------#
# select_attr - function to determine which persistent and/or        #
#   dynamic attributes should be displayed.                          #
#                                                                    #
# Parameters:                                                        #
#   $session          input   RMC session handle.                    #
#   $resource         in      Resource class name.                   #
#   $req_properties   in      Return attributes with these props.    #
#   @$r_attr_names    in      reference to list of attributes        #
#   @$r_pattr_names   in/out  reference to list of persistent attr.  #
#   @$r_dattr_names   in/out  reference to list of dynamic attr.     #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   $Opt_LS_Class     input   TRUE if display resource class versus  #
#                             the resource.                          #
#   $Opt_LS_PAttr     in/out  TRUE if display persistent attributes. #
#                             Set to FALSE if all attr specified in  #
#                             $r_attr_names are dynamic.             #
#   $Opt_LS_DAttr     in/out  TRUE if display dynamic attributes.    #
#                             FALSE if not displaying any dyna attr. #
#                             Set to FALSE if all attr specified in  #
#                             $r_attr_names are dynamic.             #
#--------------------------------------------------------------------#
sub select_attr
{
my ($session, $resource, $req_properties, $r_attr_names, 
    $r_pattr_names, $r_dattr_names) = @_;

my @LoPAttrDefs = ();                   # Pers Attr Names, the key
                                        # in HoPAttrDefs in rsp order
my %HoPAttrDefs = ();                   # Complex Hash of Persistent
                                        # attr names and definitions

my @LoDAttrDefs = ();                   # Dynam Attr Names, the key in
                                        # in HoDAttrDefs in rsp order
my %HoDAttrDefs = ();                   # Complex Hash of Dynamic

my $attribute;
my $rc = 0;

# If we are to display persistent attributes or a list of attribute
# names were specified on the command line we need to get the
# persistent attribute definitions for all attributes that have 
# the requested property so we can build up a list of what persistent
# attributes we need to query RMC for their values.
# Remember if any attribute names was specified on the command line
# that overrides the property and the req_property was set to 0xFFFF
# by parse_cmd_line
if ($Opt_LS_PAttr || scalar(@$r_attr_names) > 0) {
    $rc = get_p_attr_defs($session, $resource, $Opt_LS_Class,
        $req_properties, $r_attr_names, \@LoPAttrDefs, \%HoPAttrDefs);
    ($rc == 0) || return($rc);
    # Build up the list of Persistent Attribute Names to be displayed

    # If no attributes were specified on the command line then 
    # all the persistent attributes returned from get_p_attr_defs
    # should get displayed.  
    if (scalar(@$r_attr_names) == 0) {
        @$r_pattr_names = @LoPAttrDefs;
    }
    # Only want the persistent attributes that were in the original 
    # command line attribute list.
    else {
        foreach $attribute (@$r_attr_names) {
            if (defined($HoPAttrDefs{$attribute})) {
                push @$r_pattr_names, $attribute;
            }
        }
    }
}

# If we are to display dynamic attributes or a list of attribute
# names were specified on the command line and they aren't all
# persistent attributes then we need to get the dynamic attribute
# definitions so we can build up a list of what dynamic attributes
# we need to query RMC for their values.
if ($Opt_LS_DAttr || ((scalar(@$r_attr_names) > 0) &&
   (scalar(@$r_attr_names) != scalar(@$r_pattr_names)))) {
    $rc = get_d_attr_defs($session, $resource, $Opt_LS_Class,
        $req_properties, $r_attr_names, \@LoDAttrDefs, \%HoDAttrDefs);
    ($rc == 0) || return($rc);

    # Build up the list of Dynamic Attribute Names to be displayed

    # If no attributes were specified on the command line then 
    # all the dynamic attributes returned from get_d_attr_defs
    # should get displayed.  
    if (scalar(@$r_attr_names) == 0) {
        @$r_dattr_names =  @LoDAttrDefs;
    }

    # Only want the dynamic attributes that were in the original 
    # command line attribute list.
    else {      
        foreach $attribute (@$r_attr_names) {
            if (defined($HoDAttrDefs{$attribute})) {
                push @$r_dattr_names, $attribute;
            }
        }
    }
}

# Verify that all the specified attributes from the command line
# are either persistent or dynamic
foreach $attribute (@$r_attr_names) {
    if (!defined($HoPAttrDefs{$attribute}) &&
        !defined($HoDAttrDefs{$attribute})) {
        printCEMsg("EMsgMCcliInvalidAttrName", $attribute);
        return(MC_CLI_USER_ERROR);
    }
}

# If we were asked to display both persistent and dynamic attributes
# but the attributes specified on the command line are only one type
# turn off the appropriate Global Variable.
if ($Opt_LS_PAttr && $Opt_LS_DAttr && scalar(@$r_attr_names) > 0) {
    if (scalar(@$r_pattr_names) == scalar(@$r_attr_names)) {
        $Opt_LS_DAttr = $FALSE;
    }
    elsif (scalar(@$r_dattr_names) == scalar(@$r_attr_names)) {
        $Opt_LS_PAttr = $FALSE;
    }
}

return $rc; 
}   # end select_attr


#--------------------------------------------------------------------#
# class_query_p - function to call the CT::MC::class_query_p_bp      #
#   extension and handle possible errors.                            #
#                                                                    #
# Parameters:                                                        #
#   $session          input   RMC session handle.                    #
#   $resource         in      Resource class name.                   #
#   @$r_attr_names    in      reference to List of attributes        #
#   $attr_count       in      0 for all                              #
#                                                                    #
#   @$rLoPAttr        in/out  Reference to an ordered list of        #
#                             persistent attribute names.            #
#   %$rHoPAttr        in/out  Reference to a hash of attributes.     #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   $Opt_Class_Def    input   TRUE if display resource class def     #
#                             versus the resource def.               #
#   $Fkey_Attr_Name   input   Attribute name to associate HoPAttr    #
#                             to HoDAttr. It's value is a resource   #
#                             handle.                                #
#--------------------------------------------------------------------#
sub class_query_p
{
my ($session, $resource, $r_attributes, $rLoPAttr, $rHoPAttr) = @_;
my ($rc, $err_rc) = 0;
 
# Need a Response Class
my $response = CT::MC::class_query_rsp_t->new;

my $error = CT::MC::errnum_t->new;

# MC_SELECT_ALL

my $attr_count = scalar(@$r_attributes);

$Trace && print STDERR "Calling CT::MC::class_query_p_bp\n";

$rc = CT::MC::class_query_p_bp($session, $response, $error,
                                $resource, 
                                $r_attributes, $attr_count);

$Trace && print STDERR "Return  CT::MC::class_query_p_bp\n";

$rc = error_check("mc_class_query_p_bp", $resource, $response, 
    $rc, $error);
($rc != 0) && return $rc;

# Build the list of ordered persistent attributes
# Its easier to manipulate a Hash of Persistent Attributes
# for searching, but we want to display them in the order that we
# got them from RMC.
# For each attribute in the response, if its not already
# in the List of Attribute Names (%$rLoPAttr) add it, if its
# not already in the Hash of Attributes add it.
my %elements = ();
my $attribute = CT::MC::attribute_t->new();
$attr_count = $response->attr_count;
my $rsrc_hndl_key;
($rc, $rsrc_hndl_key) = string_to_rsrc_handle("0x00");
if ($attr_count > 0) {
    $attribute->init($response->attrs, $attr_count);
    $attribute->init($response->attrs, $attr_count);
    # Need to insert a foreign key to associate the responses
    # from the class_query_d with class_query_p
    # Since there is only one response for class just use 
    # a resource handle of all 0s (0,0,0,...) as the foreign key 
    # that will allow for consistency between resource and 
    # resource class HoAttr foreign key

    # This name must be unique and since real attribute names
    # are supposed to only be alphanumeric the * should guarantee
    # uniqueness. This resource handle is the foreign key 
    # between the resources in HoPAttr and HoDAttr
    $attr_name = $Fkey_Attr_Name; 
    $elements{at_name}  = $attr_name;
    $elements{at_dtype} = CT_RSRC_HANDLE_PTR;
    $elements{at_value} = $rsrc_hndl_key;  
    build_HoAttr($attr_name, $rLoPAttr, $rHoPAttr, \%elements, 0);
}
for ($i = 0; $i < $attr_count; $i++) {
    $attr_name = $attribute->at_name($i);
    # Build up the complex data structure for the
    # new attribute
    %elements = ();
    $elements{at_name}  = $attr_name;
    $elements{at_id}    = $attribute->at_id($i);
    $elements{at_dtype} = $attribute->at_dtype($i);
    $elements{at_value} = $attribute->at_value($i);
    build_HoAttr($attr_name, $rLoPAttr, $rHoPAttr, \%elements, 0);
}   # for $i < $attr_cnt

# Free the response 
$rc = CT::MC::free_response($response);

return $rc;
}   # end class_query_p 


#--------------------------------------------------------------------#
# class_query_d - function to call the CT::MC::class_query_d_bp      #
#   extension and handle possible errors.                            #
#                                                                    #
# For details see class_query_p                                      #
#--------------------------------------------------------------------#
sub class_query_d
{
my ($session, $resource, $r_attributes, $rLoDAttr, $rHoDAttr) = @_;
my ($rc, $err_rc) = 0;

# Need a Response Class
my $response = CT::MC::class_query_rsp_t->new;

my $error = CT::MC::errnum_t->new;

# MC_SELECT_ALL

my $attr_count = scalar(@$r_attributes);

$Trace && print STDERR "Calling CT::MC::class_query_d_bp\n";

$rc = CT::MC::class_query_d_bp($session, $response, $error,
                                $resource,
                                $r_attributes, $attr_count);

$Trace && print STDERR "Return  CT::MC::class_query_d_bp\n";

$rc = error_check("mc_class_query_d_bp", $resource, $response, 
    $rc, $error); 
($rc != 0) && return $rc;

# Build the list of ordered dynamic attributes
# Its easier to manipulate a Hash of Dynamic Attributes
# for searching, but we want to display them in the order that we
# got them from RMC.
# For each attribute in the response, if its not already
# in the List of Attribute Names (%$rLoDAttr) add it, if its
# not already in the Hash of Attributes add it.
my %elements = ();
my $attribute = CT::MC::attribute_t->new();
# TODO: If we change format of resource handle this will need 
# to change.
my $rsrc_hndl_key;
($rc, $rsrc_hndl_key) = string_to_rsrc_handle("0x00"); 
$attr_count = $response->attr_count;
if ($attr_count > 0) {
    $attribute->init($response->attrs, $attr_count);
    # Need to insert a foreign key to associate the responses
    # from the class_query_d with class_query_p
    # Since there is only one response for class just use 
    # a resource handle of 0s (0,0,0,...) as the foreign key 
    # that will allow for consistency between resource and 
    # resource class HoAttr foreign key

    # This name must be unique and since real attribute names
    # are supposed to only be alphanumeric the * should guarantee
    # uniqueness. This resource handle is the foreign key 
    # between the resources in HoPAttr and HoDAttr
    $attr_name = $Fkey_Attr_Name; 
    $elements{at_name}  = $attr_name;
    $elements{at_dtype} = CT_RSRC_HANDLE_PTR;
    $elements{at_value} = $rsrc_hndl_key;  
    build_HoAttr($attr_name, $rLoDAttr, $rHoDAttr, \%elements, 0);
}
for ($i = 0; $i < $attr_count; $i++) {
    $attr_name = $attribute->at_name($i);
    # Build up the complex data structure for the
    # new attribute
    %elements = ();
    $elements{at_name}  = $attr_name;
    $elements{at_id}    = $attribute->at_id($i);
    $elements{at_dtype} = $attribute->at_dtype($i);
    $elements{at_value} = $attribute->at_value($i);
    build_HoAttr($attr_name, $rLoDAttr, $rHoDAttr, \%elements, 0);
}   # for $i < $attr_cnt

# Free the response
$rc = CT::MC::free_response($response);

return $rc;
}   # end class_query_d


#--------------------------------------------------------------------#
# query_p_select - function to call the CT::MC::query_p_select_bp    #
#   extension and handle possible errors.                            #
#                                                                    #
# Parameters:                                                        #
#   $session          input   RMC session handle.                    #
#   $resource         in      Resource class name.                   #
#   $select_str       in      Selection string.                      #
#   @$r_attr_names    in      reference to List of attributes        #
#   $attr_count       in      0 for all                              #
#                                                                    #
#   @$rLoPAttr        in/out  Reference to an ordered list of        #
#                             persistent attribute names.            #
#   %$rHoPAttr        in/out  Reference to a hash of attributes.     #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   $Opt_Class_Def    input   TRUE if display resource class def     #
#                             versus the resource def.               #
#--------------------------------------------------------------------#
sub query_p_select
{
my ($session, $resource, $select_str, $r_attributes, 
    $rLoPAttr, $rHoPAttr) = @_;
my ($rc, $err_rc) = 0;
 
# Need a Response for Persistent Attributes
my $response = CT::MC::query_rsp_t->new;

my $error = CT::MC::errnum_t->new;

# MC_SELECT_ALL

my $attr_count = scalar(@$r_attributes);

$Trace && print STDERR "Calling CT::MC::query_p_select_bp\n";

$rc = CT::MC::query_p_select_bp($session, $response, $error,
                                $resource, $select_str,
                                $r_attributes, $attr_count);

$Trace && print STDERR "Return  CT::MC::query_p_select_bp\n";

$rc = error_check("mc_query_p_select_bp", $resource, $response, 
    $rc, $error); 
#($rc != 0) && return $rc;

# Build the list of ordered persistent attributes
# Its easier to manipulate a Hash of Persistent Attributes
# for searching, but we want to display them in the order that we
# got them from RMC.  
# For each attribute in the response, if its not already 
# in the List of Attribute Names (%$rLoPAttr) add it, if its
# not already in the Hash of Attributes add it.
my %elements = ();
my $rr = -1;
my $response_cnt = $response->array_count;
# if query_p_select_bp had an error and no data was returned, exit
if (($response_cnt <= 0) && ($rc != 0) ) { return $rc;}
# save the query_p_select_bp return code for later
my $query_rc = $rc;
my $attribute = CT::MC::attribute_t->new();
for (my $r = 0; $r < $response_cnt; $r++) {
    my $attr_count = $response->attr_count($r);
    if ($attr_count > 0) {
        $rr++;
        $attribute->init($response->attrs($r), $attr_count); 
        # We need to save the response's resource handle because
        # this is the resource handle we use to associate
        # the persistent attribute response with the dynamic attr
        # response 
        %elements = ();
        # This name must be unique and since real attribute names
        # are supposed to only be alphanumeric the * should guarantee
        # uniqueness. This resource handle is the foreign key 
        # between the resources in HoPAttr and HoDAttr
        $attr_name = $Fkey_Attr_Name; 
        $elements{at_name}  = $attr_name;
        $elements{at_dtype} = CT_RSRC_HANDLE_PTR;
        $elements{at_value} = $response->rsrc_hndl($r); 
        build_HoAttr($attr_name, $rLoPAttr, $rHoPAttr, \%elements, $rr);
    }
    for (my $i = 0; $i < $attr_count; $i++) {
        $attr_name = $attribute->at_name($i);
        # Build up the complex data structure for the 
        # new attribute
        %elements = ();
        $elements{at_name}  = $attr_name;
        $elements{at_id}    = $attribute->at_id($i);
        $elements{at_dtype} = $attribute->at_dtype($i);
        $elements{at_value} = $attribute->at_value($i); 
        build_HoAttr($attr_name, $rLoPAttr, $rHoPAttr, \%elements, $rr);
    }   # for $i < $attr_cnt
}   # for $r < $response_cnt 

# Free the response - if there was one
if ($response->array_count > 0) {
    $rc = CT::MC::free_response($response);
}

if ($query_rc != 0) { return $query_rc;}
else { return $rc; }
}   # end query_p_select


#--------------------------------------------------------------------#
# query_d_select - function to call the CT::MC::query_d_select_bp    #
#   extension and handle possible errors.                            #
#                                                                    #
# For details see query_p_select.                                    #
#--------------------------------------------------------------------#
sub query_d_select
{
my ($session, $resource, $select_str, $r_attributes,
    $rLoDAttr, $rHoDAttr) = @_;
my ($rc, $err_rc) = 0;

# Need a Response for Dynamic Attributes
my $response = CT::MC::query_rsp_t->new;

my $error = CT::MC::errnum_t->new;

# MC_SELECT_ALL

my $attr_count = scalar(@$r_attributes);

$Trace && print STDERR "Calling CT::MC::query_d_select_bp\n";

$rc = CT::MC::query_d_select_bp($session, $response, $error,
                                $resource, $select_str,
                                $r_attributes, $attr_count);

$Trace && print STDERR "Return  CT::MC::query_d_select_bp\n";

$rc = error_check("mc_query_d_select_bp", $resource, $response, 
    $rc, $error);
#($rc != 0) && return $rc;

# Build the list of ordered dynamic attributes
# Its easier to manipulate a Hash of Dynamic Attributes
# for searching, but we want to display them in the order that we
# got them from RMC.
# For each attribute in the response, if its not already
# in the List of Attribute Names (%$rLoDAttr) add it, if its
# not already in the Hash of Attributes add it.
my %elements = ();
my $rr = -1;
my $response_cnt = $response->array_count;
# if query_d_select_bp had an error and no data was returned, exit
if (($response_cnt <= 0) && ($rc != 0) ) { return $rc;}
# save the query_p_select_bp return code for later
my $query_rc = $rc;
my $attribute = CT::MC::attribute_t->new();
for (my $r = 0; $r < $response_cnt; $r++) {
    my $attr_count = $response->attr_count($r);
    if ($attr_count > 0) {
        $rr++;
        $attribute->init($response->attrs($r), $attr_count);
        # We need to save the response's resource handle because
        # this is the resource handle we use to associate
        # the persistent attribute response with the dynamic attr
        # response 
        %elements = ();
        # This name must be unique and since real attribute names
        # are supposed to only be alphanumeric the * should guarantee
        # uniqueness. This resource handle is the foreign key 
        # between the resources in HoPAttr and HoDAttr
        $attr_name = $Fkey_Attr_Name;
        $elements{at_name}  = $attr_name;
        $elements{at_dtype} = CT_RSRC_HANDLE_PTR;
        $elements{at_value} = $response->rsrc_hndl($r); 
        build_HoAttr($attr_name, $rLoDAttr, $rHoDAttr, \%elements, $rr);
    }
    for (my $i = 0; $i < $attr_count; $i++) {
        $attr_name = $attribute->at_name($i);
        # Build up the complex data structure for the 
        # new attribute
        %elements = ();
        $elements{at_name}  = $attr_name;
        $elements{at_id}    = $attribute->at_id($i);
        $elements{at_dtype} = $attribute->at_dtype($i);
        $elements{at_value} = $attribute->at_value($i);
        build_HoAttr($attr_name, $rLoDAttr, $rHoDAttr, \%elements, $rr);
    }   # for $i < $attr_cnt
}   # for $r < $response_cnt 

# Free the response - if there was one
if ($response->array_count > 0) {
    $rc = CT::MC::free_response($response);
}

if ($query_rc != 0) { return $query_rc;}
else { return $rc; }
}   # end query_d_select


#--------------------------------------------------------------------#
# format_resource_handles - copies the array of resource handles     #
#   into the complex hash format that is required by the utility:    #
#   CT_cli_display_utils::display_resource_data.                     #
#                                                                    #
# Parameters:                                                        #
#   @$r_rsrc_handles  input   Array of resource handles.             #
#   @$rLoAttr         in/out  Reference to List of Attributes Names  #
#   %$rHoAttr         in/out  Reference to Hash of Attributes        #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub format_resource_handles
{
my ($r_rsrc_handles, $rLoAttr, $rHoAttr) = @_;

# We only need to display one attribute, the resource handle.
# But for ease of display we need to put it in the complex format
# that MC_cli_display_utils::display_resource_data requires, which 
# is basically a matrix of attributes. Though we only have
# one attribute to format, ResourceHandle, there may be 0 or 
# more instances of a resource handle to be displayed. 
my %elements = ();
my $attr_name = "ResourceHandle";
my $rsrc_handle_cnt = scalar(@$r_rsrc_handles);
for (my $i = 0; $i < $rsrc_handle_cnt; $i++) {
    # Build up the complex data structure for the
    # new attribute
    %elements = ();
    $elements{at_name}  = $attr_name;
    $elements{at_id}    = 0; 
    $elements{at_dtype} = CT_RSRC_HANDLE_PTR; 
    $elements{at_value} = $r_rsrc_handles->[$i];

    # build_HoAttr not only builds this complex hash one attribute at
    # a time but it also will build an array with the names of the 
    # attributes that you want to display. Again, in this case that
    # is simply ResourceHandle.
    build_HoAttr($attr_name, $rLoAttr, $rHoAttr, \%elements, $i);
}   # for $i < $rsrc_handle_cnt

return;
}   # end format_resource_handles


#--------------------------------------------------------------------#
# display_resource - displays the actual resource attribute names    #
#   and values using the appropriate output format (long,            #
#   delimitter, or tabular).                                         #
#                                                                    #
# Parameters:                                                        #
#   @$r_attributes    input   Attribute names from command line.     #
#   @$rLoAttr         input   Reference to List of Attributes Names  #
#   %$rHoAttr         input   Reference to Hash of Attributes        #
#                                                                    #
# Returns:                                                           #
#   $rc                       0 - if success, otherwise failure.     #
#                                                                    #
# Global References:                                                 #
#   $Opt_LS_RHandle   input   TRUE if displaying resource handles.   #
#   $Opt_LS_Class     input   TRUE if displaying resource class.     #
#   $Opt_LS_PAttr     input   TRUE if displaying pers attributes.    #
#   $Opt_LS_DAttr     input   TRUE if displaying dyna attributes.    #
#   $Opt_Long_Format  input   TRUE if should display one per line.   #
#   $Opt_Table_Format input   TRUE if should display in table form.  #
#   $Opt_Delm_Format  input   TRUE if should display with delimiter. #
#   $Opt_Delm_Str     input   Actual delimiter to display with.      #
#   $Opt_No_HDR       input   TRUE if should not display header.     #
#--------------------------------------------------------------------#
sub display_resource
{
my($r_attributes, $rLoAttr, $rHoAttr, $type) = @_;

my $header;
my @title_row;
my $print_format = "long";             
my $delim = "";

# Determine if displaying in long, delimiter or tabular/column format.
if ($Opt_Long_Format) {
    $print_format = "long";
}
elsif ($Opt_Table_Format) {
    $print_format = "column";
}
elsif ($Opt_Delm_Format) {
    $print_format = "delim";
    $delim = $Opt_Delm_Str;
}

# Instead of using the display_resource_data to display the header
# use printIMsg so the header can be properly translated (NLS).
$header = "";
if (!$Opt_No_HDR) {
    if ($Opt_LS_RHandle) { 
        printIMsg("IMsglsrsrcLsRsrcHndlHdr", $resource);
    }
    elsif ($Opt_LS_Input_File && $Opt_LS_Class) {
       print "PersistentResourceClassAttributes::\n";
    }
    elsif ($Opt_LS_Input_File) {
       print "PersistentResourceAttributes::\n";
    }
    elsif ($Opt_LS_PAttr && !$Opt_LS_DAttr) {
        ($Opt_LS_Class) ? 
            printIMsg("IMsglsrsrcLsRsrcClassPAttrHdr", $resource) :  
            printIMsg("IMsglsrsrcLsRsrcPAttrHdr", $resource); 
    }
    else {
        ($Opt_LS_Class) ? 
            printIMsg("IMsglsrsrcLsRsrcClassDAttrHdr", $resource) :
            printIMsg("IMsglsrsrcLsRsrcDAttrHdr", $resource);
    }
}

($Opt_LS_Class) ? 
    $title_row = "resource_class" : 
    $title_row = "resource";

# if it's for file input, always use "resource"
if ($Opt_LS_Input_File) { 
    $title_row = "resource";
}

# Display the attributes in the order that they were requested
# on the command line.  If no attribute names were specified on 
# the command line display them in the order that RMC returned 
# them.

if (scalar(@$r_attributes) == 0) { 
    foreach $attr_name (@$rLoAttr) {
        ($attr_name eq $Fkey_Attr_Name) && next;
        push @$r_attributes, $attr_name;
    } 
}

# For debugging to reference one element 
# $rHoAttr->{$attr_name}[$row]{at_value} 

my $rc = display_resource_data($print_format, $Opt_No_HDR,
    $r_attributes, $title_row, $rHoAttr, $delim, $header);

return $rc;
}   # end display_resource


#--------------------------------------------------------------------#
# display_joined_resource - displays both the persistent and dynamic #
#   attribute names and their values using the appropriate output    #
#   format (long, delimitter, or tabular).                           #
#                                                                    #
# Parameters:                                                        #
#   @$r_attributes    input   Attribute names from command line.     #
#   @$rLoPAttr        input   Reference to List of Pers Attr Names.  #
#   %$rHoPAttr        input   Reference to Hash of Pers Attrs.       #
#   @$rLoDAttr        input   Reference to List of Dyna Attr Names.  #
#   %$rHoDAttr        input   Reference to Hash of Dyna Attrs.       #
#                                                                    #
# Returns:                                                           #
#   $rc                       0 - success, otherwise failure.        #
#                                                                    #
# Global References:                                                 #
#   $Opt_LS_Class     input   TRUE if displaying resource class.     #
#   $Opt_Long_Format  input   TRUE if should display one per line.   #
#   $Opt_Table_Format input   TRUE if should display in table form.  #
#   $Opt_Delm_Format  input   TRUE if should display with delimiter. #
#   $Opt_Delm_Str     input   Actual delimiter to display with.      #
#   $Opt_No_HDR       input   TRUE if should not display header.     #
#--------------------------------------------------------------------#
sub display_joined_resource
{
my ($r_attributes, $rLoPAttr, $rHoPAttr, 
    $rLoDAttr, $rHoDAttr, $type) = @_;

my $header;
my @title_row;
my $print_format = "long";        
my $delim = "";

# Determine if displaying in long, delimiter or tabular/column format.
if ($Opt_Long_Format) {
    $print_format = "long";
}
elsif ($Opt_Table_Format) {
    $print_format = "column";
}
elsif ($Opt_Delm_Format) {
    $print_format = "delim";
    $delim = $Opt_Delm_Str;
}

if (!$Opt_No_HDR) {
    ($Opt_LS_Class) ? 
        printIMsg("IMsglsrsrcLsRsrcClassPAttrDAttrHdr", $resource) : 
        printIMsg("IMsglsrsrcLsRsrcPAttrDAttrHdr", $resource);
}

($Opt_LS_Class) ? 
    $title_row = "resource_class" :
    $title_row = "resource";

# For debugging to reference one element 
# $rHoPAttr->{$attr_name}[$row]{at_value} 
# $rHoDAttr->{$attr_name}[$row]{at_value}

my $rc = display_joined_resource_data($print_format, $Opt_No_HDR, 
    $r_attributes, $title_row, $rHoPAttr, $rHoDAttr, $delim, $header);

return $rc;
}   # end display_joined_resource


#--------------------------------------------------------------------#
# error_check - checks the return code from the RMC function and     #
#   the error response return code.  If an error is detected         #
#   appropriate error messages will be displayed.                    #
#                                                                    #
# Parameters:                                                        #
#   $rmc_function     in      Name of the rmc function that was      #
#                             called and whose error code we are     #
#                             checking.                              #
#   $rmc_class        in      The rmc resource class name.           #
#   $response         in      RMC response.                          #
#   $rmc_rc           in      The rmc function return code.          #
#   $error            in      The error response.                    #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check 
{
my ($rmc_function, $rmc_class, $response, $rmc_rc, $error) = @_;

my $rc = 0;
my $err_rc = $error->errnum();

if ($rmc_rc != 0) {
    printEMsg("EMsglsrsrcLsRsrcError", $rmc_class);
    my $rmc_rc_hex = sprintf "0x%8.8lx", $rmc_rc;
    printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function,
        $rmc_rc, $rmc_rc_hex);
    $rc = MC_CLI_RMC_ERROR;
    return $rc;
}

# Check the errnum in each of the RMC responses
for (my $r = 0; $r < $response->array_count; $r++) {
    # get the error that goes with the specific response
    if ($r > 0) {
        $response->error($error, $r);
        $err_rc = $error->errnum();
    }
    if ($err_rc != 0) {
        if ($err_rc == RMC_ECLASSNOTDEFINED) {
            printCEMsg("EMsgMCcliClassNotDef", $rmc_class);
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc == RMC_EBADATTRNAM) {
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }   
        elsif ($err_rc == RMC_ENORSRCSFOUND) {
            # Just because no resources found doesn't mean this
            # is an error.
            $Verbose && print STDERR $error->error_msg;
            #$rc = 0;
        }
        elsif ($err_rc == RMC_EACCESS) {
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc == RMC_EALLQUANTUM) {
            # Just because all dynamic resources are quantum 
            # doesn't mean this is an error.
            $Verbose && print STDERR $error->error_msg;
            #$rc = 0;
        }
        elsif ($err_rc >= 0x60000 && $err_rc <= 0x6ffff) {
            # Selection string errors are in this range
            printCEMsg("EMsgMCcliSelectStrError");
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        else {
            printEMsg("EMsglsrsrcLsRsrcError", $rmc_class);
            my $err_rc_hex = sprintf "0x%8.8lx", $err_rc;
            printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function,
                $err_rc, $err_rc_hex);
            print STDERR $error->error_msg;
            $rc = MC_CLI_RMC_ERROR;
        }
    }   # end if
}   # end for

return $rc;
}   # end error_check
